home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / tex / cawf404.zip / expand.c < prev    next >
C/C++ Source or Header  |  1993-12-07  |  8KB  |  309 lines

  1. /*
  2.  *    expand.c - macro expansion functions for cawf(1)
  3.  */
  4.  
  5. /*
  6.  *    Copyright (c) 1991 Purdue University Research Foundation,
  7.  *    West Lafayette, Indiana 47907.  All rights reserved.
  8.  *
  9.  *    Written by Victor A. Abell <abe@mace.cc.purdue.edu>,  Purdue
  10.  *    University Computing Center.  Not derived from licensed software;
  11.  *    derived from awf(1) by Henry Spencer of the University of Toronto.
  12.  *
  13.  *    Permission is granted to anyone to use this software for any
  14.  *    purpose on any computer system, and to alter it and redistribute
  15.  *    it freely, subject to the following restrictions:
  16.  *
  17.  *    1. The author is not responsible for any consequences of use of
  18.  *       this software, even if they arise from flaws in it.
  19.  *
  20.  *    2. The origin of this software must not be misrepresented, either
  21.  *       by explicit claim or by omission.  Credits must appear in the
  22.  *       documentation.
  23.  *
  24.  *    3. Altered versions must be plainly marked as such, and must not
  25.  *       be misrepresented as being the original software.  Credits must
  26.  *       appear in the documentation.
  27.  *
  28.  *    4. This notice may not be removed or altered.
  29.  */
  30.  
  31. #include "cawf.h"
  32.  
  33. /*
  34.  * Expand(line) - expand macro or if/ie/el line
  35.  */
  36.  
  37. void
  38. Expand(line)
  39.     unsigned char *line;
  40. {
  41.     unsigned char buf[2*MAXLINE];    /* line buffer */
  42.     unsigned char cmd[4];        /* nroff command */
  43.     int cmdl;            /* command length */
  44.     int cmdx;            /* cmd index in Macrotab[] */
  45.     int cond = 0;            /* conditional statuses */
  46.     int i, j;            /* temporary indexes */
  47.     int iflen;            /* if statement length */
  48.     int invert;            /* inversion status */
  49.     unsigned char *lp;        /* line pointer */
  50.     int mx = -1;            /* Macrotab[] index */
  51.     int n1, n2;            /* temporary numbers */
  52.     int nargs = 0;            /* number of arguments */
  53.     int nleft = 0;            /* number of macro lines left */
  54.     char op;            /* comparison operator */
  55.     int prevcond;            /* previous condition (for else's) */
  56.     int ptr = -1;            /* Macrotxt[] index */
  57.     int quote;            /* quoted string status */
  58.     unsigned char *s1, *s2;        /* temporary string pointers */
  59.  
  60.  
  61.     (void) sprintf((char *)buf, ".^= %d %s", NR, (char *)Inname);
  62.     Pass2(buf);
  63.  
  64.     for (lp = line; *lp; ) {
  65.         invert = regexec(Pat[1].pat, lp);
  66.         prevcond = cond;
  67.         cond = 0;
  68.         if (regexec(Pat[0].pat, lp) == 0) {
  69.         /*
  70.          * Not conditional: - ! "^[.'](i[ef]|el)"
  71.          */
  72.             cond = 1;
  73.             iflen = 0;
  74.         }
  75.  
  76.         else if (regexec(Pat[2].pat, lp)) {
  77.         /*
  78.          * Argument count comparison: -
  79.          *        "^[.']i[ef] !?\\n\(\.\$(>|>=|=|<|<=)[0-9] "
  80.          */
  81.             iflen = strlen(".if \\n(.$=n ") + invert;
  82.             s1 = lp + iflen - 3;
  83.             op = *s1++;
  84.             if (*s1 == '=' && (op == '>' || op == '<')) {
  85.                 s1++;
  86.                 op = (op == '>') ? 'G' : 'L';
  87.             }
  88.             n1 = (int)(*s1 - '0');
  89.             switch (op) {
  90.                 case '=':
  91.                     if ((nargs - 1) == n1)
  92.                         cond = 1;
  93.                     break;
  94.                 case '<':
  95.                     if ((nargs - 1) < n1)
  96.                         cond = 1;
  97.                     break;
  98.                 case '>':
  99.                     if ((nargs - 1) > n1)
  100.                         cond = 1;
  101.                     break;
  102.                 case 'G':    /* >= */
  103.                     if ((nargs - 1) >= n1)
  104.                         cond = 1;
  105.                     break;
  106.                 case 'L':    /* <= */
  107.                     if ((nargs - 1) <= n1)
  108.                         cond = 1;
  109.             }
  110.         }
  111.         
  112.         else if (regexec(Pat[3].pat, lp)) {
  113.         /*
  114.          * Argument string comparison: - "^[.']i[ef] !?'\\\$[0-9]'[^']*' "
  115.          */
  116.             iflen = strlen(".if '\\$n'") + invert;
  117.             n1 = (int)(*(lp + iflen - 2) - '0');
  118.             if (n1 >= 0 && n1 < nargs)
  119.                 s1 = Args[n1];
  120.             else
  121.                 s1 = (unsigned char *)"";
  122.             if ((s2 = (unsigned char *)strchr((char *)lp
  123.                   + iflen, '\''))
  124.             != NULL) {
  125.                 n2 = s2 - lp - iflen;
  126.                 if (strncmp((char *)s1, (char *)lp + iflen, n2)
  127.                 == 0)
  128.                     cond = 1;
  129.                 iflen += n2 + 2;
  130.             }
  131.         }
  132.         
  133.         else if (regexec(Pat[4].pat, lp)) {
  134.         /*
  135.          * Nroff or troff: - "^[.']i[ef] !?[nt] "
  136.          */
  137.             iflen = strlen(".if n ") + invert;
  138.             if (*(lp + iflen - 2) == 'n')
  139.                 cond = 1;
  140.         }
  141.         
  142.         else if ((*lp == '.' || *lp == '\'')
  143.              &&  strncmp((char *)lp+1, "el ", 3) == 0) {
  144.         /*
  145.          * Else clause: - "^[.']el "
  146.          */
  147.             cond = 1 - prevcond;
  148.             iflen = 4;
  149.         }
  150.         
  151.         else {
  152.         /*
  153.          * Unknown conditional:
  154.          */
  155.             cond = 1;
  156.             iflen = 0;
  157.             (void) sprintf((char *)buf,
  158.                 ".tm unknown .if/.ie form: %s", (char *)lp);
  159.             lp = buf;
  160.         }
  161.        /*
  162.         * Handle conditional.  If case is true, locate predicate.
  163.         * If predicate is an .i[ef], process it.
  164.         */
  165.         if (invert)
  166.             cond = 1 - cond;
  167.         if (cond && iflen > 0) {
  168.             lp += iflen;
  169.             if (regexec(Pat[15].pat, lp))
  170.                 continue;
  171.         }
  172.         /*
  173.          * Do argument substitution, as necessary.
  174.          */
  175.         if (cond && regexec(Pat[5].pat, lp)) {      /* "\$[0-9]" ??? */
  176.             for (s1 = buf;;) {
  177.                 if ((n1 = Pat[5].pat->startp[0] - lp) > 0) {
  178.                     (void) strncpy((char *)s1, (char *)lp,
  179.                         n1);
  180.                     s1 += n1;
  181.                 }
  182.                 *s1 = '\0';
  183.                 lp = Pat[5].pat->endp[0];
  184.                 n1 = (int)(*(lp-1) - '0');
  185.                 if (n1 >= 0 && n1 < nargs) {
  186.                     (void) strcpy((char *)s1,
  187.                         (char *)Args[n1]);
  188.                     s1 += strlen((char *)Args[n1]);
  189.                 }
  190.                 if (*lp == '\0')
  191.                     break;
  192.                 if (regexec(Pat[5].pat, lp) == 0) {
  193.                     (void) strcpy((char *)s1, (char *)lp);
  194.                     break;
  195.                 }
  196.             }
  197.             lp = buf;
  198.         }
  199.         /*
  200.          * Check for nroff command.
  201.          */
  202.         if (cond) {
  203.             cmdl = 0;
  204.             if (cond && (*lp == '.' || *lp == '\'')) {
  205.                 if ((*cmd = *(lp+1)) != '\0') {
  206.                     cmdl++;
  207.                     if ((*(cmd+1) = *(lp+2)) == ' ')
  208.                         *(cmd+1) = '\0';
  209.                     else
  210.                         cmdl++;
  211.                 }
  212.             }
  213.             cmd[cmdl] = '\0';
  214.         }
  215.         if (cond == 0)
  216.             i = i;        /* do nothing if condition is false */
  217.         else if (cmdl == 0 || ((cmdx = Findmacro(cmd, 0)) < 0))
  218.             Pass2(lp);
  219.         else if (Sp >= MAXSP) {
  220.             (void) sprintf((char *)buf, " macro nesting > %d",
  221.                 MAXSP);
  222.             Error(WARN, LINE, (char *)buf, NULL);
  223.         } else {
  224.         /*
  225.          * Stack macros.
  226.          */
  227.           /*
  228.            * Push stack.
  229.            */
  230.             Sp++;
  231.             Nleftstack[Sp] = nleft;
  232.             Ptrstack[Sp] = ptr;
  233.             Mxstack[Sp] = mx;
  234.             Condstack[Sp] = cond;
  235.             for (i = 10*Sp, j = 0; j < 10; i++, j++) {
  236.                 Argstack[i] = Args[j];
  237.                 Args[j] = NULL;
  238.             }
  239.            /*
  240.             * Start new stack entry.
  241.             */
  242.             mx = cmdx;
  243.             ptr = Macrotab[mx].bx;
  244.             cond = 0;
  245.             nleft = Macrotab[mx].ct;
  246.             Args[0] = Newstr(cmd);
  247.            /*
  248.             * Parse arguments.
  249.             */
  250.             for (s1 = lp + cmdl + 1, nargs = 1; nargs < 10;) {
  251.                 while (*s1 && (*s1 == ' ' || *s1 == '\t'))
  252.                     s1++;
  253.                 if (*s1 == '\0')
  254.                     break;
  255.                 if (*s1 == '"') {
  256.                     s1++;
  257.                     quote = 1;
  258.                 } else
  259.                     quote = 0;
  260.                 for (s2 = buf;;) {
  261.                     if (!quote && (*s1 == ' ' || *s1 == '\t')) {
  262.                     *s2 = '\0';
  263.                     break;
  264.                     }
  265.                     if ((*s2 = *s1) == '\0')
  266.                     break;
  267.                     s1++;
  268.                     if (quote && *s2 == '"') {
  269.                     *s2 = '\0';
  270.                     break;
  271.                     }
  272.                     s2++;
  273.                     }
  274.                 if (buf[0])
  275.                     Args[nargs++] = Newstr(buf);
  276.             }
  277.             for (i = nargs; i < 10; i++) {
  278.                 Args[i] = NULL;
  279.             }
  280.         }
  281.         /*
  282.          * Unstack completed macros.
  283.          */
  284.         while (nleft <= 0 && Sp >= 0) {
  285.             nleft = Nleftstack[Sp];
  286.             mx = Mxstack[Sp];
  287.             ptr = Ptrstack[Sp];
  288.             cond = Condstack[Sp];
  289.             for (i = 10*Sp, j = 0, nargs = -1; j < 10; i++, j++) {
  290.                 Free(&Args[j]);
  291.                 if ((Args[j] = Argstack[i]) != NULL)
  292.                     nargs = j;
  293.             }
  294.             Sp--;
  295.             nargs++;
  296.         }
  297.         /*
  298.          * Get next line.
  299.          */
  300.         if (nleft > 0) {
  301.             lp = Macrotxt[ptr++];
  302.             nleft--;
  303.         } else
  304.             lp = (unsigned char *)"";
  305.     }
  306.     (void) sprintf((char *)buf, ".^# %d %s", NR, (char *)Inname);
  307.     Pass2(buf);
  308. }
  309.